#include "napi/native_api.h"
#include <cstdint>
#include <napi/common.h>
#include <thread>
#include "uv.h"

//static napi_value Demo1(napi_env env, napi_callback_info info){
//    size_t argc;
//    napi_value argv[10] = {nullptr};
//    napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr);
//    return nullptr;
//}
//
//
//static napi_value Demo2(napi_env env, napi_callback_info info){
//    size_t argc = 5;
//    napi_value argv[3] = {nullptr};
//    napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr);
//    return nullptr;
//}
//
//static napi_value Demo3(napi_env env, napi_callback_info info){
//    size_t argc = 0;
//    napi_get_cb_info(env, info, &argc, nullptr, nullptr, nullptr);
//    if(argc==0){
//        return nullptr;
//    }
//    napi_value* argv = new napi_value[argc];
//    napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr);
//    // 业务代码
//    delete argv;
//    return nullptr;
//}
//
//static napi_value Demo4(napi_env env, napi_callback_info info){
//    size_t argc = 2;
//    napi_value argv[2] = {nullptr};
//    napi_get_cb_info(env, info, &argc, nullptr, nullptr, nullptr);
//    
//    // 业务代码
//    return nullptr;
//}


static napi_value Test(){
//    napi_event_mode_default
//    napi_event_mode_nowait
//    napi_threadsafe_function
//    napi_release_threadsafe_function
//napi_acquire_threadsafe_function
}

//static void DerefItem(napi_env env, void *data, void *hint){
//    Object *obj = reinterpret_cast<Object *>(data);
//    delete obj;
//}
//
//static napi_value Wrap(napi_env env, napi_callback_info info){
//    size_t argc = 1;
//    napi_value toWrap;
//    auto status = napi_get_cb_info(env, info, &argc, &toWrap, NULL, NULL);
//    if(status != napi_ok){
//        return nullptr;
//    }
//    struct Object *obj = new struct Object();
//    obj->name = 'liLei';
//    obj->age = 18;
//    status = napi_wrap(env, toWrap, reinterpret_cast<void *>(obj), DerefItem, NULL, NULL);
//    if(status != napi_ok){
//        return nullptr;
//    }
//    return toWrap;
//}
/*  execute in main thread */
//static napi_value DemoInMainThread(napi_env env, napi_callback_info info){
//    napi_value string = nullptr;
//    napi_create_string_utf8(env, "bar", NAPI_AUTO_LENGTH, &string);
//    napi_create_reference(env, string, 1, &g_ref);
//    return string;
//}
///*  execute in worker thread */
//static napi_value DemoInWorkerThread(napi_env env, napi_callback_info info){
//    napi_value string = nullptr;
//    napi_get_reference_value(env, g_ref, &string);
//    napi_value object = nullptr;
//    napi_create_object(env, &object);
//    napi_set_named_property(env, object, "foo", string);
//    return object;
//}

static napi_value Demo(napi_env env, napi_callback_info info){
    size_t argc = 1;
    napi_value args[1] = {nullptr};
    napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
    napi_value sizeObj = nullptr;
    napi_handle_scope scope = nullptr;
    napi_open_handle_scope(env, &scope);
    napi_call_function(env, nullptr, args[0], 0, nullptr, &sizeObj);
    napi_close_handle_scope(env, scope);
    
    int64_t width = 0;
    napi_value result = nullptr;
    napi_get_element(env, sizeObj, 0, &result);
    napi_get_value_int64(env, result, &width);
    return result;
}


struct CallbackContext {
    napi_env env = nullptr;
    napi_ref callbackRef = nullptr;
    int32_t retData = 0;
};

void callbackTest(CallbackContext *context){
    uv_loop_s *loop = nullptr;
    napi_get_uv_event_loop(context->env, &loop);
    uv_work_t *work = new uv_work_t;
    context->retData = 1;
    work->data = (void *)context;
    uv_queue_work(loop, work, [](uv_work_t* work){}, [](uv_work_t *work, int status){
        CallbackContext *context = (CallbackContext *)work->data;

        napi_value callback = nullptr;
        napi_get_reference_value(context->env, context->callbackRef, &callback);
        napi_value retArg;
        napi_create_int32(context->env, context->retData, &retArg);
        napi_value ret;
        napi_call_function(context->env, nullptr, callback, 1, &retArg, &ret);
        napi_delete_reference(context->env, context->callbackRef);
        if(work!= nullptr){
            delete work;
        }
        delete context;
    });
}

static napi_value Demoo(napi_env env, napi_callback_info info){
    constexpr size_t arrSize = 1000;
    napi_value arrBuffer = nullptr;
    void *data = nullptr;
    napi_create_arraybuffer(env, arrSize * sizeof(int32_t), &data, &arrBuffer);
    int32_t *i32Buffer = reinterpret_cast<int32_t *>(data);
    for(int i=0; i < arrSize; i++){
        i32Buffer[i] = i;
    }
    return arrBuffer;
}


static napi_value CreateBigintWords(napi_env env, napi_callback_info info){
    int signBit = 0;
    size_t wordCount = 3;
    uint64_t words[] = {12ULL, 34ULL, 56ULL};
    napi_value returnValue = nullptr;
    napi_status status = napi_create_bigint_words(env, signBit, wordCount, words, &returnValue);
    if(status != napi_ok){
        napi_throw_error(env, nullptr, "napi_create_bigint fail");
        return nullptr;
    }
    return returnValue;
}

static napi_value GetArrayLength(napi_env env, napi_callback_info info){
    size_t argc = 1;
    napi_value args[1] = {nullptr};
    napi_value result;
    uint32_t length;
    napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
    bool is_array;
    napi_is_array(env, nullptr, &is_array);
    
}

static napi_value GetBufferInfo(napi_env env, napi_callback_info info){
    std::string str("GetBufferInfo");
    napi_value buffer = nullptr;
    void *bufferPtr = nullptr;
    size_t bufferSize = str.size();
    napi_create_buffer(env, bufferSize, &bufferPtr, &buffer);
    strcpy((char *)bufferPtr, str.data());
}


// entry/src/main/cpp/napi_init.cpp
static napi_value CallNative(napi_env env, napi_callback_info info)
{
    size_t argc = 2;
    // 声明参数数组
    napi_value args[2] = {nullptr};

    // 获取传入的参数并依次放入参数数组中
    napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);

    // 依次获取参数
    double value0;
    napi_get_value_double(env, args[0], &value0);
    double value1;
    napi_get_value_double(env, args[1], &value1);

    // 返回两数相加的结果
    napi_value sum;
    napi_create_double(env, value0 + value1, &sum);
    return sum;
}

static napi_value NativeCallArkTS(napi_env env, napi_callback_info info)
{    
    size_t argc = 1;
    // 声明参数数组
    napi_value args[1] = {nullptr};

    // 获取传入的参数并依次放入参数数组中
    napi_get_cb_info(env, info, &argc, args , nullptr, nullptr);

    // 创建一个int，作为ArkTS的入参
    napi_value argv = nullptr;    
    napi_create_int32(env, 2, &argv );

    // 调用传入的callback，并将其结果返回
    napi_value result = nullptr;
    napi_call_function(env, nullptr, args[0], 1, &argv, &result);
    return result;
}


static napi_value Add(napi_env env, napi_callback_info info)
{
    size_t argc = 2;
    napi_value args[2] = {nullptr};

    napi_get_cb_info(env, info, &argc, args , nullptr, nullptr);

    napi_valuetype valuetype0;
    napi_typeof(env, args[0], &valuetype0);

    napi_valuetype valuetype1;
    napi_typeof(env, args[1], &valuetype1);

    double value0;
    napi_get_value_double(env, args[0], &value0);

    double value1;
    napi_get_value_double(env, args[1], &value1);

    napi_value sum;
    napi_create_double(env, value0 + value1, &sum);

    return sum;

}

EXTERN_C_START
static napi_value Init(napi_env env, napi_value exports)
{
    napi_property_descriptor desc[] = {
        {"callNative", nullptr, CallNative, nullptr, nullptr, nullptr, napi_default, nullptr},
        {"nativeCallArkTS", nullptr, NativeCallArkTS, nullptr, nullptr, nullptr, napi_default, nullptr},
        { "add", nullptr, Add, nullptr, nullptr, nullptr, napi_default, nullptr }
    };
    napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc);
    return exports;
}
EXTERN_C_END

static napi_module demoModule = {
    .nm_version = 1,
    .nm_flags = 0,
    .nm_filename = nullptr,
    .nm_register_func = Init,
    .nm_modname = "entry",
    .nm_priv = ((void*)0),
    .reserved = { 0 },
};

extern "C" __attribute__((constructor)) void RegisterEntryModule(void)
{
    napi_module_register(&demoModule);
}
